here_long <-  -122.3095
here_lat <- 47.6560
seattle = get_map(location = c(here_long, here_lat), zoom = 13, maptype = 'roadmap')
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=47.656,-122.3095&zoom=13&size=640x640&scale=2&maptype=roadmap&language=en-EN&sensor=false
spd.911 <- spd.911 %>% 
             rowwise() %>% 
             mutate(dist=distVincentyEllipsoid(c(Longitude, Latitude), c(here_long, here_lat)))              
nrow(spd.911)
[1] 257011
descriptions <- c("STRONG ARM ROBBERY", "PERSON WITH A WEAPON (NOT GUN)", "HAZARDS", "HARASSMENT, THREATS", "FIGHT DISTURBANCE", "CRISIS COMPLAINT - GENERAL", "ARMED ROBBERY")
# Removes Specifically Harassment by Telephone and Writing, as well as other non-scary crimes
data.ped <- spd.911 %>% filter(str_detect(Event.Clearance.Description, paste(descriptions, collapse="|"))) %>% filter(!str_detect(Event.Clearance.Description, "HARASSMENT, THREATS - BY TELEPHONE, WRITING")) %>% filter(!str_detect(Event.Clearance.Description, "HARBOR DEBRIS, NAVIGATIONAL HAZARDS"))
nrow(data.ped)
[1] 15606
data.here <- data.ped %>% filter(dist < 2600)
data.w.at.scene <- filter(data.here, !is.na(at_scene_time_date))
data <- data.w.at.scene
nrow(data)
[1] 722
# View(data)
write.csv(data, '2016-2017-Clean.csv')
data <- read.csv('2016-2017-Clean.csv', header = TRUE)
# View(data)
data <- filter(data, !str_detect(Event.Clearance.Description, "HARBOR - DEBRIS, NAVIGATIONAL HAZARDS"))
nrow(data)
[1] 710
ggmap(seattle) +
   geom_point(data = data, aes(x = Longitude, y = Latitude), colour = "red", alpha = 0.75)

  #coord_map()
cor(1:12, data.frame(by.month)$Freq)
[1] 0.4616517
freq_by_desc <- table(droplevels(data$Event.Clearance.Description))
# View(freq_by_desc)
ggplot(as.data.frame(freq_by_desc), 
       aes(x = Var1, y = Freq)) +
       geom_bar(stat = 'identity') +# create bar plot
    coord_flip()

#Traffic related calls, suspicious circumstances, and disturbances are the the most significant threats to pedestrations
        
ggmap(seattle) +
  geom_point(data = data, aes(x = Longitude, y = Latitude, group = Event.Clearance.Description, color = Event.Clearance.Description), alpha = 0.5, size = 10) +
  facet_wrap(~ Event.Clearance.Description) +
  theme(axis.ticks = element_blank(), 
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        strip.text = element_text(size=50),
        legend.position = "none"
        )

# selecting just ID and location data
df_loc <- data %>% dplyr::select(CAD.CDW.ID, Longitude, Latitude)
# figuring out number of clusters
wss <- c()
# clusters 1 to 15
for (i in 1:15) {
  wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
}
plot(1:15, wss, type="b", xlab="Number of Clusters",
  ylab="Within groups sum of squares")

# fitting model
fit <- kmeans(df_loc, 10)
fit$centers # look at cluster sizes and means. want clusters to be about equal size
   CAD.CDW.ID Longitude Latitude
1     1966835 -122.3188 47.65906
2     2093969 -122.3142 47.65982
3     2116300 -122.3129 47.66095
4     1899308 -122.3154 47.66025
5     2046956 -122.3160 47.65922
6     2071185 -122.3156 47.66114
7     1864428 -122.3118 47.66149
8     2022152 -122.3172 47.66033
9     1994531 -122.3159 47.66109
10    1932836 -122.3171 47.66133
fit$cluster
  [1]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [40]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [79]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[118]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[157]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4 10 10 10 10 10 10 10 10
[196] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[235] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[274] 10 10 10 10 10 10 10 10 10  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[313]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[352]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[391]  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[430]  9  9  9  9  9  9  9  9  9  9  9  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[469]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[508]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
[547]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[586]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[625]  6  6  6  6  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
[664]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3  3  3  3  3  3
[703]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
[742]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
cluster.size <- data.frame(1:10, fit$size)
cluster.size
ggplot(data = cluster.size, aes(x = X1.10, y = fit.size)) +
  geom_bar(stat = 'identity')

ggplot()

ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
aggregate(df_loc, by=list(fit$cluster), FUN=mean)
df_loc
# adding data back into dataframe 
# df_loc <- df_loc %>% mutate(cluster = fit$cluster) 
# View(data)
by_month <- table(data$event_clearance_month)
by_month <- table(data$event_clearance_month)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiRXJyb3I6IGF0dGVtcHQgdG8gdXNlIHplcm8tbGVuZ3RoIHZhcmlhYmxlIG5hbWVcbiJ9 -->

Error: attempt to use zero-length variable name ```

# hundred block vs TOD
  
by_hr <- table(data$event_clearance_hr)
by_hr

  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23 
 38  28  31  52  20  16  17  15  14  16  12  36  20  32  36  39  43  24  25 115  21  38  40  37 
ggplot(as.data.frame(by_hr), aes(x = Var1, y = Freq)) + 
  geom_point() +
  xlab('hour of day')

ggplot(data, aes(x = event_clearance_ts, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

ggplot(data, aes(x = Hundred.Block.Location, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

  
# selecting just ID and location data
df_loc <- data.w.at.scene %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
Error in eval(lhs, parent, parent) : object 'data.w.at.scene' not found
#some useful functions for performing clustering
#extract the lat and long from a dataframe, and run kmeans on it
# x = one of our dataframes
# clusters = how many centers you want kmeans to work with when clustering
fit.clusters <- function(x, clusters) {
  # selecting just ID and location data
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  # fitting model
  fit <- kmeans(df_loc, clusters)
  fit$centers # look at cluster sizes and means. want clusters to be about equal size
  return(fit)
}
#make a plot that will tell you how many clusters might work for a given dataframe
# x = a dataframe
# max = the maximum number of clusters you want to try
find.num.clusters <- function(x, max) {
  if(max > nrow(x)) { stop('Cannot fit more clusters than there are rows in dataframe')}
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  wss = c()
  for (i in 1:max) {
    wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
  }
  plot(1:max, wss, type="b", xlab="Number of Clusters",
     ylab="Within groups sum of squares")
}
#plot the number of observations in each cluster
# x = a fit object returned from kmeans() or the fit.clusters() function above
plot.cluster.sizes <- function(x) {
  cluster.size <- data.frame(data.frame('clusters' = 1:nrow(x$centers), x$size))
  ggplot(data = cluster.size, aes(x = clusters, y = x.size)) +
  geom_bar(stat = 'identity')
}

Clustering by time of day

morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.28889
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 74
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 176
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

#take out general crisis complaint - general
data <- filter(data, Event.Clearance.Description != 'CRISIS COMPLAINT - GENERAL')
morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.69318
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] HAZARDS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] HARASSMENT, THREATS FIGHT DISTURBANCE  
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] STRONG ARM ROBBERY
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 48
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 107
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJSIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cH0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKTsKIyBpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpOwpsaWJyYXJ5KHRpZHl2ZXJzZSkKcmVxdWlyZSgibWFwcyIpCmxpYnJhcnkoZ2Vvc3BoZXJlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KG1hcHRvb2xzKQppZiAoIXJlcXVpcmUoZ2dtYXApKSB7IGluc3RhbGwucGFja2FnZXMoJ2dnbWFwJyk7IHJlcXVpcmUoZ2dtYXApIH0KbGlicmFyeShnZ21hcCkKcGF0aC50by5jc3YgPC0gJ34vRG93bmxvYWRzL1NlYXR0bGVfUG9saWNlX0RlcGFydG1lbnRfOTExX0luY2lkZW50X1Jlc3BvbnNlICgxKS5jc3YnCnNwZC45MTEgPC0gcmVhZC5jc3YocGF0aC50by5jc3YsIGhlYWRlciA9IFRSVUUpCgpzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5EYXRlLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkKc3BkLjkxMSRjbGVhcmFuY2VfZGF0ZV9kYXRlID0gYXMuRGF0ZShzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cyA9IGFzLlBPU0lYY3Qoc3RycHRpbWUoc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuRGF0ZSwgIiVtLyVkLyVZICVJOiVNOiVTICVwIikpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RhdGUgPSBhcy5EYXRlKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV9tb250aCA9IG1vbnRoKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RheSA9IHdlZWtkYXlzKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RhdGUpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2hyID0gaG91cih5bWRfaG1zKGFzLmNoYXJhY3RlcihzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cykpKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV9tbiA9IG1pbnV0ZSh5bWRfaG1zKGFzLmNoYXJhY3RlcihzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cykpKQpzcGQuOTExJEluaXRpYWwuVHlwZS5Hcm91cCA9IGZhY3RvcihzcGQuOTExJEluaXRpYWwuVHlwZS5Hcm91cCkKc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuR3JvdXAgPSBmYWN0b3Ioc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuR3JvdXApCnNwZC45MTEkWm9uZS5CZWF0ID0gZmFjdG9yKHNwZC45MTEkWm9uZS5CZWF0KQpzcGQuOTExJERpc3RyaWN0LlNlY3RvciA9IGZhY3RvcihzcGQuOTExJERpc3RyaWN0LlNlY3RvcikKc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF5ID0gZmFjdG9yKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RheSkKCnNwZC45MTEkYXRfc2NlbmVfdGltZV90cyA9IGFzLlBPU0lYY3Qoc3RycHRpbWUoc3BkLjkxMSRBdC5TY2VuZS5UaW1lLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkgI2NvbnZlcnRpbmcgdGltZSBmcm9tIFN0cmluZyB0byBkYXRlIGFuZCB0aW1lIHJlcHJlc2VudGF0aW9uIChQT1NJWGN0KQpzcGQuOTExJGF0X3NjZW5lX3RpbWVfaHIgPSBob3VyKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkYXRfc2NlbmVfdGltZV90cykpKQpzcGQuOTExJGF0X3NjZW5lX3RpbWVfZGF0ZSA9IGFzLkRhdGUoc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzKQpzcGQuOTExJHRpbWVfdW50aWxfZXZlbnRfY2xlYXIgPSBhcy5udW1lcmljKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzIC0gc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzKQoKCgojIHBhdGggdG8gdGhlIEZPTERFUiB3aXRoIHRoZSAuc2hwIGZpbGUgaW4gaXQuIHRoZSBzZWNvbmQgcGFyYW0gaXMgdGhlIG5hbWUgb2YgdGhlIC5zaHAgZmlsZQojIHNlYXR0bGUgPC0gcmVhZE9HUihkc24gPSBwYXRoLmV4cGFuZCgifi9kb2N1bWVudHMvSU5GTzM3MC9wcm9qZWN0LXRlYW1uYW1lLXYyL21hcHMtYXBpLXRlc3QiKSwgbGF5ZXIgPSAiU2VhdHRsZV9DaXR5X0xpbWl0cyIpCgojIHVzYSA8LSBtYXBfZGF0YSgic3RhdGUiKQojIGRhdGEgPC0gbWVyZ2UodXNhLCBzcGQuOTExKQojIFJlZCBTcXVhcmUgY29vcmRpbmF0ZXMKaGVyZV9sb25nIDwtICAtMTIyLjMwOTUKaGVyZV9sYXQgPC0gNDcuNjU2MAoKc2VhdHRsZSA9IGdldF9tYXAobG9jYXRpb24gPSBjKGhlcmVfbG9uZywgaGVyZV9sYXQpLCB6b29tID0gMTMsIG1hcHR5cGUgPSAncm9hZG1hcCcpCgpgYGAKCgpgYGB7cn0Kc3BkLjkxMSA8LSBzcGQuOTExICU+JSAKICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiUgCiAgICAgICAgICAgICBtdXRhdGUoZGlzdD1kaXN0VmluY2VudHlFbGxpcHNvaWQoYyhMb25naXR1ZGUsIExhdGl0dWRlKSwgYyhoZXJlX2xvbmcsIGhlcmVfbGF0KSkpICAgICAgICAgICAgICAKbnJvdyhzcGQuOTExKQoKZGVzY3JpcHRpb25zIDwtIGMoIlNUUk9ORyBBUk0gUk9CQkVSWSIsICJQRVJTT04gV0lUSCBBIFdFQVBPTiAoTk9UIEdVTikiLCAiSEFaQVJEUyIsICJIQVJBU1NNRU5ULCBUSFJFQVRTIiwgIkZJR0hUIERJU1RVUkJBTkNFIiwgIkNSSVNJUyBDT01QTEFJTlQgLSBHRU5FUkFMIiwgIkFSTUVEIFJPQkJFUlkiKQoKIyBSZW1vdmVzIFNwZWNpZmljYWxseSBIYXJhc3NtZW50IGJ5IFRlbGVwaG9uZSBhbmQgV3JpdGluZywgYXMgd2VsbCBhcyBvdGhlciBub24tc2NhcnkgY3JpbWVzCmRhdGEucGVkIDwtIHNwZC45MTEgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiwgcGFzdGUoZGVzY3JpcHRpb25zLCBjb2xsYXBzZT0ifCIpKSkgJT4lIGZpbHRlcighc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sICJIQVJBU1NNRU5ULCBUSFJFQVRTIC0gQlkgVEVMRVBIT05FLCBXUklUSU5HIikpICU+JSBmaWx0ZXIoIXN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCAiSEFSQk9SIERFQlJJUywgTkFWSUdBVElPTkFMIEhBWkFSRFMiKSkKbnJvdyhkYXRhLnBlZCkKCmRhdGEuaGVyZSA8LSBkYXRhLnBlZCAlPiUgZmlsdGVyKGRpc3QgPCAyNjAwKQoKZGF0YS53LmF0LnNjZW5lIDwtIGZpbHRlcihkYXRhLmhlcmUsICFpcy5uYShhdF9zY2VuZV90aW1lX2RhdGUpKQpkYXRhIDwtIGRhdGEudy5hdC5zY2VuZQpucm93KGRhdGEpCiMgVmlldyhkYXRhKQoKd3JpdGUuY3N2KGRhdGEsICcyMDE2LTIwMTctQ2xlYW4uY3N2JykKYGBgCgpgYGB7cn0KZGF0YSA8LSByZWFkLmNzdignMjAxNi0yMDE3LUNsZWFuLmNzdicsIGhlYWRlciA9IFRSVUUpCiMgVmlldyhkYXRhKQpkYXRhIDwtIGZpbHRlcihkYXRhLCAhc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sICJIQVJCT1IgLSBERUJSSVMsIE5BVklHQVRJT05BTCBIQVpBUkRTIikpCm5yb3coZGF0YSkKZ2dtYXAoc2VhdHRsZSkgKwogICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgY29sb3VyID0gInJlZCIsIGFscGhhID0gMC43NSkKCmBgYAoKYGBge3J9CiNjaGVjayBmcmVxdWVuY3kgYnkgbW9udGgKYnkubW9udGggPC0gdGFibGUoZGF0YSRldmVudF9jbGVhcmFuY2VfbW9udGgpCmRhdGEuZnJhbWUoYnkubW9udGgpCmNvcigxOjEyLCBkYXRhLmZyYW1lKGJ5Lm1vbnRoKSRGcmVxKQoKZ2dwbG90KGFzLmRhdGEuZnJhbWUoYnkubW9udGgpLCAKICAgICAgIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEpKSArCiAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKYGBgCgpgYGB7cn0KZnJlcV9ieV9kZXNjIDwtIHRhYmxlKGRyb3BsZXZlbHMoZGF0YSRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pKQojIFZpZXcoZnJlcV9ieV9kZXNjKQoKZ2dwbG90KGFzLmRhdGEuZnJhbWUoZnJlcV9ieV9kZXNjKSwgCiAgICAgICBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxKSkgKwogICAgICAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpICsjIGNyZWF0ZSBiYXIgcGxvdAogICAgY29vcmRfZmxpcCgpCgojVHJhZmZpYyByZWxhdGVkIGNhbGxzLCBzdXNwaWNpb3VzIGNpcmN1bXN0YW5jZXMsIGFuZCBkaXN0dXJiYW5jZXMgYXJlIHRoZSB0aGUgbW9zdCBzaWduaWZpY2FudCB0aHJlYXRzIHRvIHBlZGVzdHJhdGlvbnMKCiAgICAgICAgCmBgYAoKYGBge3IgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTIwfQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSwgZ3JvdXAgPSBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sIGNvbG9yID0gRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKSwgYWxwaGEgPSAwLjUsIHNpemUgPSAxMCkgKwogIGZhY2V0X3dyYXAofiBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pICsKICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NTApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICAgICAgICkKYGBgCgpgYGB7cn0KIyBzZWxlY3RpbmcganVzdCBJRCBhbmQgbG9jYXRpb24gZGF0YQpkZl9sb2MgPC0gZGF0YSAlPiUgZHBseXI6OnNlbGVjdChDQUQuQ0RXLklELCBMb25naXR1ZGUsIExhdGl0dWRlKQoKIyBmaWd1cmluZyBvdXQgbnVtYmVyIG9mIGNsdXN0ZXJzCndzcyA8LSBjKCkKIyBjbHVzdGVycyAxIHRvIDE1CmZvciAoaSBpbiAxOjE1KSB7CiAgd3NzW2ldIDwtIHN1bShrbWVhbnMoZGZfbG9jLCBjZW50ZXJzPWkpJHdpdGhpbnNzKQp9CnBsb3QoMToxNSwgd3NzLCB0eXBlPSJiIiwgeGxhYj0iTnVtYmVyIG9mIENsdXN0ZXJzIiwKICB5bGFiPSJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikKCiMgZml0dGluZyBtb2RlbApmaXQgPC0ga21lYW5zKGRmX2xvYywgMTApCmZpdCRjZW50ZXJzICMgbG9vayBhdCBjbHVzdGVyIHNpemVzIGFuZCBtZWFucy4gd2FudCBjbHVzdGVycyB0byBiZSBhYm91dCBlcXVhbCBzaXplCmZpdCRjbHVzdGVyCmNsdXN0ZXIuc2l6ZSA8LSBkYXRhLmZyYW1lKDE6MTAsIGZpdCRzaXplKQpjbHVzdGVyLnNpemUKCmdncGxvdChkYXRhID0gY2x1c3Rlci5zaXplLCBhZXMoeCA9IFgxLjEwLCB5ID0gZml0LnNpemUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpCmdncGxvdCgpCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwphZ2dyZWdhdGUoZGZfbG9jLCBieT1saXN0KGZpdCRjbHVzdGVyKSwgRlVOPW1lYW4pCgpkZl9sb2MKCiMgYWRkaW5nIGRhdGEgYmFjayBpbnRvIGRhdGFmcmFtZSAKIyBkZl9sb2MgPC0gZGZfbG9jICU+JSBtdXRhdGUoY2x1c3RlciA9IGZpdCRjbHVzdGVyKSAKCiMgVmlldyhkYXRhKQpgYGAKCmBgYHtyfQojIGRpc3RyaWJ1dGlvbiBvZiBjcmltZXMgYnkgbW9udGgKYnlfbW9udGggPC0gdGFibGUoZGF0YSRldmVudF9jbGVhcmFuY2VfbW9udGgpCmJ5X21vbnRoCmBgYAoKYGBge3J9CiMgaHVuZHJlZCBibG9jayB2cyBUT0QKICAKYnlfaHIgPC0gdGFibGUoZGF0YSRldmVudF9jbGVhcmFuY2VfaHIpCmJ5X2hyCmdncGxvdChhcy5kYXRhLmZyYW1lKGJ5X2hyKSwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICB4bGFiKCdob3VyIG9mIGRheScpCgoKCmdncGxvdChkYXRhLCBhZXMoeCA9IGV2ZW50X2NsZWFyYW5jZV90cywgeSA9IHRpbWVfdW50aWxfZXZlbnRfY2xlYXIpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjI1KQoKZ2dwbG90KGRhdGEsIGFlcyh4ID0gSHVuZHJlZC5CbG9jay5Mb2NhdGlvbiwgeSA9IHRpbWVfdW50aWxfZXZlbnRfY2xlYXIpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjI1KQogIAoKIyBzZWxlY3RpbmcganVzdCBJRCBhbmQgbG9jYXRpb24gZGF0YQpkZl9sb2MgPC0gZGF0YS53LmF0LnNjZW5lICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExhdGl0dWRlLCBMb25naXR1ZGUpCgojIGZpZ3VyaW5nIG91dCBudW1iZXIgb2YgY2x1c3RlcnMKd3NzIDwtIGMoKQojIGNsdXN0ZXJzIDEgdG8gMTUKZm9yIChpIGluIDE6MTUpIHsKICB3c3NbaV0gPC0gc3VtKGttZWFucyhkZl9sb2MsIGNlbnRlcnM9aSkkd2l0aGluc3MpCn0KcGxvdCgxOjE1LCB3c3MsIHR5cGU9ImIiLCB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMiLAogIHlsYWI9IldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQoKIyBmaXR0aW5nIG1vZGVsCmZpdCA8LSBrbWVhbnMoZGZfbG9jLCA1KQpmaXQkY2VudGVycyAjIGxvb2sgYXQgY2x1c3RlciBzaXplcyBhbmQgbWVhbnMuIHdhbnQgY2x1c3RlcnMgdG8gYmUgYWJvdXQgZXF1YWwgc2l6ZQpmaXQkY2x1c3RlcgpjbHVzdGVyLnNpemUgPC0gZGF0YS5mcmFtZSgxOjUsIGZpdCRzaXplKQpjbHVzdGVyLnNpemUKCmdncGxvdChkYXRhID0gY2x1c3Rlci5zaXplLCBhZXMoeCA9IFgxLjUsIHkgPSBmaXQuc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKZ2dwbG90KCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCmFnZ3JlZ2F0ZShkZl9sb2MsIGJ5PWxpc3QoZml0JGNsdXN0ZXIpLCBGVU49bWVhbikKCmRmX2xvYwpgYGAKCmBgYHtyfQojc29tZSB1c2VmdWwgZnVuY3Rpb25zIGZvciBwZXJmb3JtaW5nIGNsdXN0ZXJpbmcKCiNleHRyYWN0IHRoZSBsYXQgYW5kIGxvbmcgZnJvbSBhIGRhdGFmcmFtZSwgYW5kIHJ1biBrbWVhbnMgb24gaXQKIyB4ID0gb25lIG9mIG91ciBkYXRhZnJhbWVzCiMgY2x1c3RlcnMgPSBob3cgbWFueSBjZW50ZXJzIHlvdSB3YW50IGttZWFucyB0byB3b3JrIHdpdGggd2hlbiBjbHVzdGVyaW5nCmZpdC5jbHVzdGVycyA8LSBmdW5jdGlvbih4LCBjbHVzdGVycykgewogICMgc2VsZWN0aW5nIGp1c3QgSUQgYW5kIGxvY2F0aW9uIGRhdGEKICBkZl9sb2MgPC0geCAlPiUgZHBseXI6OnNlbGVjdChDQUQuQ0RXLklELCBMYXRpdHVkZSwgTG9uZ2l0dWRlKQoKICAjIGZpdHRpbmcgbW9kZWwKICBmaXQgPC0ga21lYW5zKGRmX2xvYywgY2x1c3RlcnMpCiAgZml0JGNlbnRlcnMgIyBsb29rIGF0IGNsdXN0ZXIgc2l6ZXMgYW5kIG1lYW5zLiB3YW50IGNsdXN0ZXJzIHRvIGJlIGFib3V0IGVxdWFsIHNpemUKICByZXR1cm4oZml0KQp9CgojbWFrZSBhIHBsb3QgdGhhdCB3aWxsIHRlbGwgeW91IGhvdyBtYW55IGNsdXN0ZXJzIG1pZ2h0IHdvcmsgZm9yIGEgZ2l2ZW4gZGF0YWZyYW1lCiMgeCA9IGEgZGF0YWZyYW1lCiMgbWF4ID0gdGhlIG1heGltdW0gbnVtYmVyIG9mIGNsdXN0ZXJzIHlvdSB3YW50IHRvIHRyeQpmaW5kLm51bS5jbHVzdGVycyA8LSBmdW5jdGlvbih4LCBtYXgpIHsKICBpZihtYXggPiBucm93KHgpKSB7IHN0b3AoJ0Nhbm5vdCBmaXQgbW9yZSBjbHVzdGVycyB0aGFuIHRoZXJlIGFyZSByb3dzIGluIGRhdGFmcmFtZScpfQogIGRmX2xvYyA8LSB4ICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExhdGl0dWRlLCBMb25naXR1ZGUpCiAgd3NzID0gYygpCiAgZm9yIChpIGluIDE6bWF4KSB7CiAgICB3c3NbaV0gPC0gc3VtKGttZWFucyhkZl9sb2MsIGNlbnRlcnM9aSkkd2l0aGluc3MpCiAgfQogIHBsb3QoMTptYXgsIHdzcywgdHlwZT0iYiIsIHhsYWI9Ik51bWJlciBvZiBDbHVzdGVycyIsCiAgICAgeWxhYj0iV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpCn0KCiNwbG90IHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIGVhY2ggY2x1c3RlcgojIHggPSBhIGZpdCBvYmplY3QgcmV0dXJuZWQgZnJvbSBrbWVhbnMoKSBvciB0aGUgZml0LmNsdXN0ZXJzKCkgZnVuY3Rpb24gYWJvdmUKcGxvdC5jbHVzdGVyLnNpemVzIDwtIGZ1bmN0aW9uKHgpIHsKICBjbHVzdGVyLnNpemUgPC0gZGF0YS5mcmFtZShkYXRhLmZyYW1lKCdjbHVzdGVycycgPSAxOm5yb3coeCRjZW50ZXJzKSwgeCRzaXplKSkKICBnZ3Bsb3QoZGF0YSA9IGNsdXN0ZXIuc2l6ZSwgYWVzKHggPSBjbHVzdGVycywgeSA9IHguc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKfQpgYGAKIyNDbHVzdGVyaW5nIGJ5IHRpbWUgb2YgZGF5CmBgYHtyfQptb3JuaW5nIDwtIGZpbHRlcihkYXRhLCA2IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxMCApCm1pZC5kYXkgPC0gIGZpbHRlcihkYXRhLCAxMCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTQgKQphZnRlcm5vb24gPC0gIGZpbHRlcihkYXRhLCAxNCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTggKQpldmVuaW5nIDwtICBmaWx0ZXIoZGF0YSwgMTggPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDIyICkKbmlnaHQgPC0gIGZpbHRlcihkYXRhLCAyMiA8PSBhdF9zY2VuZV90aW1lX2hyIHwgYXRfc2NlbmVfdGltZV9ociA8IDIgKQplYXJseS5tb3JuaW5nIDwtICBmaWx0ZXIoZGF0YSwgMiA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgNiApCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbW9ybmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1pZC5kYXksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhZnRlcm5vb24sIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBldmVuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbmlnaHQsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBlYXJseS5tb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpsZW5ndGhzIDwtIGMobnJvdyhtb3JuaW5nKSwgbnJvdyhtaWQuZGF5KSwgbnJvdyhhZnRlcm5vb24pLCBucm93KGV2ZW5pbmcpLCBucm93KG5pZ2h0KSwgbnJvdyhlYXJseS5tb3JuaW5nKSkKbmFtZXMgPC0gYygnTW9ybmluZ1xuNjowMCAtIDk6NTknLCAnTWlkLWRheVxuMTA6MDAgLSAxOjU5JywgJ0FmdGVybm9vblxuMjowMCAtIDU6NTknLCAnRXZlbmluZ1xuNjowMCAtIDk6NTknLCAnTmlnaHRcbjEwOjAwIC0gMTo1OScsICdFYXJseSBNb3JuaW5nXG4yOjAwIC0gNTo1OScpCmJ5LnRvZCA8LSBkYXRhLmZyYW1lKCdUT0QnID0gbmFtZXMsICdDb3VudC5DcmltZXMnID0gbGVuZ3RocykKYnkudG9kJFRPRCA9IGZhY3RvcihieS50b2QkVE9ELCBsZXZlbHMgPSBieS50b2QkVE9EKQoKZ2dwbG90KGJ5LnRvZCwgYWVzKHggPSBUT0QsIHkgPSBDb3VudC5DcmltZXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oc3RhdCA9ICdpZGVudGl0eScpCgojIGZpbmQgdGhlIG1vZGUgb2YgbnVtZXJpYy9jaGFyYWN0ZXIgZGF0YQpNb2RlIDwtIGZ1bmN0aW9uKHgpIHsKICB1eCA8LSB1bmlxdWUoeCkKICB0YWIgPC0gdGFidWxhdGUobWF0Y2goeCwgdXgpKTsgdXhbdGFiID09IG1heCh0YWIpXQp9Cgp0b2QubWVhbiA8LSBtZWFuKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKdG9kLm1lZCA8LSBtZWRpYW4oZGF0YSRhdF9zY2VuZV90aW1lX2hyKQp0b2QubWVhbgp0b2QubWVkCk1vZGUoZGF0YSRhdF9zY2VuZV90aW1lX2hyKQoKI1doYXQgaXMgdGhlIG1vc3QgY29tbW9uIGNyaW1lIGNvbW1pdHRlZCBhdCBlYWNoIHBlcmlvZD8KTW9kZShtb3JuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShtaWQuZGF5JEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShhZnRlcm5vb24kRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGV2ZW5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKG5pZ2h0JEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShlYXJseS5tb3JuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKCiNmaXQga21lYW5zIGNsdXN0ZXJpbmcgdG8gZWFjaCB0aW1lIHBlcmlvZC4KbnJvdyhtb3JuaW5nKQpmaW5kLm51bS5jbHVzdGVycyhtb3JuaW5nLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhtb3JuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhhZnRlcm5vb24sIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKG1pZC5kYXksIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCm5yb3coYWZ0ZXJub29uKQpmaW5kLm51bS5jbHVzdGVycyhhZnRlcm5vb24sIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZmluZC5udW0uY2x1c3RlcnMoZXZlbmluZywgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMoZXZlbmluZywgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZmluZC5udW0uY2x1c3RlcnMobmlnaHQsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKG5pZ2h0LCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpgYGAKCmBgYHtyfQojdGFrZSBvdXQgZ2VuZXJhbCBjcmlzaXMgY29tcGxhaW50IC0gZ2VuZXJhbApkYXRhIDwtIGZpbHRlcihkYXRhLCBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24gIT0gJ0NSSVNJUyBDT01QTEFJTlQgLSBHRU5FUkFMJykKCm1vcm5pbmcgPC0gZmlsdGVyKGRhdGEsIDYgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDEwICkKbWlkLmRheSA8LSAgZmlsdGVyKGRhdGEsIDEwIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxNCApCmFmdGVybm9vbiA8LSAgZmlsdGVyKGRhdGEsIDE0IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxOCApCmV2ZW5pbmcgPC0gIGZpbHRlcihkYXRhLCAxOCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMjIgKQpuaWdodCA8LSAgZmlsdGVyKGRhdGEsIDIyIDw9IGF0X3NjZW5lX3RpbWVfaHIgfCBhdF9zY2VuZV90aW1lX2hyIDwgMiApCmVhcmx5Lm1vcm5pbmcgPC0gIGZpbHRlcihkYXRhLCAyIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCA2ICkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWlkLmRheSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFmdGVybm9vbiwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGV2ZW5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBuaWdodCwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGVhcmx5Lm1vcm5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmxlbmd0aHMgPC0gYyhucm93KG1vcm5pbmcpLCBucm93KG1pZC5kYXkpLCBucm93KGFmdGVybm9vbiksIG5yb3coZXZlbmluZyksIG5yb3cobmlnaHQpLCBucm93KGVhcmx5Lm1vcm5pbmcpKQpuYW1lcyA8LSBjKCdNb3JuaW5nXG42OjAwIC0gOTo1OScsICdNaWQtZGF5XG4xMDowMCAtIDE6NTknLCAnQWZ0ZXJub29uXG4yOjAwIC0gNTo1OScsICdFdmVuaW5nXG42OjAwIC0gOTo1OScsICdOaWdodFxuMTA6MDAgLSAxOjU5JywgJ0Vhcmx5IE1vcm5pbmdcbjI6MDAgLSA1OjU5JykKYnkudG9kIDwtIGRhdGEuZnJhbWUoJ1RPRCcgPSBuYW1lcywgJ0NvdW50LkNyaW1lcycgPSBsZW5ndGhzKQpieS50b2QkVE9EID0gZmFjdG9yKGJ5LnRvZCRUT0QsIGxldmVscyA9IGJ5LnRvZCRUT0QpCgpnZ3Bsb3QoYnkudG9kLCBhZXMoeCA9IFRPRCwgeSA9IENvdW50LkNyaW1lcykpICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gJ2lkZW50aXR5JykKCiMgZmluZCB0aGUgbW9kZSBvZiBudW1lcmljL2NoYXJhY3RlciBkYXRhCk1vZGUgPC0gZnVuY3Rpb24oeCkgewogIHV4IDwtIHVuaXF1ZSh4KQogIHRhYiA8LSB0YWJ1bGF0ZShtYXRjaCh4LCB1eCkpOyB1eFt0YWIgPT0gbWF4KHRhYildCn0KCnRvZC5tZWFuIDwtIG1lYW4oZGF0YSRhdF9zY2VuZV90aW1lX2hyKQp0b2QubWVkIDwtIG1lZGlhbihkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCnRvZC5tZWFuCnRvZC5tZWQKTW9kZShkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCgojV2hhdCBpcyB0aGUgbW9zdCBjb21tb24gY3JpbWUgY29tbWl0dGVkIGF0IGVhY2ggcGVyaW9kPwpNb2RlKG1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKG1pZC5kYXkkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGFmdGVybm9vbiRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoZXZlbmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUobmlnaHQkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGVhcmx5Lm1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQoKI2ZpdCBrbWVhbnMgY2x1c3RlcmluZyB0byBlYWNoIHRpbWUgcGVyaW9kLgpucm93KG1vcm5pbmcpCmZpbmQubnVtLmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobWlkLmRheSwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKbnJvdyhhZnRlcm5vb24pCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhldmVuaW5nLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhldmVuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhuaWdodCwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobmlnaHQsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKYGBgCgo=